package com.example.shardingjdbc.sharding.algorithm;

import com.example.shardingjdbc.utils.DateUtils;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import static com.example.shardingjdbc.model.constants.OperLogConstant.QUARTER_SHARDING_PATTERN;

/**
 * @Description: 操作日志范围分片算法
 * @Author: Jerry
 * @Date: 2021-08-02 23:38
 */
public class OperLogRangeShardingAlgorithm implements RangeShardingAlgorithm<Date> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Date> shardingValue) {
        Date lowerDate = shardingValue.getValueRange().lowerEndpoint();
        Date upperDate = shardingValue.getValueRange().upperEndpoint();

        LocalDate lowerLocalDate = lowerDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate upperLocalDate = upperDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        int lowerYear = lowerLocalDate.getYear();
        int lowerMonth = lowerLocalDate.getMonthValue();
        int lowerQuarter = DateUtils.getQuarterFromMonth(lowerMonth);

        int upperYear = upperLocalDate.getYear();
        int upperMonth = upperLocalDate.getMonthValue();
        int upperQuarter = DateUtils.getQuarterFromMonth(upperMonth);

        String logicTableName = shardingValue.getLogicTableName();
        Set<String> actualTableNames = new HashSet<>();

        if (lowerYear == upperYear) {
            // 不跨年
            for (int quarter = lowerQuarter; quarter <= upperQuarter; ++quarter) {
                String actualTableName = String.format(QUARTER_SHARDING_PATTERN.getVal(), logicTableName, lowerYear, quarter);
                actualTableNames.add(actualTableName);
            }
        } else {
            // 跨年
            for (int quarter = lowerQuarter; quarter <= 4; ++quarter) {
                String actualTableName = String.format(QUARTER_SHARDING_PATTERN.getVal(), logicTableName, lowerYear, quarter);
                actualTableNames.add(actualTableName);
            }

            for (int year = lowerYear + 1; year < upperYear; ++year) {
                for (int quarter = 1; quarter <= 4; ++quarter) {
                    String actualTableName = String.format(QUARTER_SHARDING_PATTERN.getVal(), logicTableName, lowerYear, quarter);
                    actualTableNames.add(actualTableName);
                }
            }

            for (int quarter = 1; quarter <= upperQuarter; ++quarter) {
                String actualTableName = String.format(QUARTER_SHARDING_PATTERN.getVal(), logicTableName, lowerYear, quarter);
                actualTableNames.add(actualTableName);
            }
        }

        if (!availableTargetNames.containsAll(actualTableNames)) {
            throw new IllegalArgumentException("分片异常！shardingValue=" + shardingValue + "; availableTargetNames=" + availableTargetNames);
        }
        return actualTableNames;
    }
}
